"""OneDrive上传操作模块

实现OneDrive的文件上传、秒传等功能。
"""

import os
import hashlib
import json
from typing import Dict, Any, Optional, List
import requests
from ..base_client import BaseCloudClient


class UploadOperations:
    """OneDrive上传操作类"""
    
    def __init__(self, client: BaseCloudClient):
        self.client = client
        self.session = client.session
    
    def check_fast_upload(self, file_path: str, parent_file_id: str = "root") -> Dict[str, Any]:
        """检查文件是否可以秒传
        
        Args:
            file_path: 本地文件路径
            parent_file_id: 父文件夹ID，默认为根目录
            
        Returns:
            检查结果，包含是否可以秒传的信息
        """
        try:
            if not os.path.exists(file_path):
                return {"success": False, "error": "文件不存在"}
            
            # OneDrive不支持传统意义上的秒传，但可以检查文件是否已存在
            file_name = os.path.basename(file_path)
            file_size = os.path.getsize(file_path)
            
            # 检查同名文件是否存在
            if parent_file_id == "root":
                url = f"https://graph.microsoft.com/v1.0/me/drive/root:/{file_name}"
            else:
                url = f"https://graph.microsoft.com/v1.0/me/drive/items/{parent_file_id}:/{file_name}"
            
            headers = {
                "Authorization": f"Bearer {self.client.access_token}"
            }
            
            response = self.session.get(url, headers=headers)
            
            if response.status_code == 200:
                existing_file = response.json()
                existing_size = existing_file.get("size", 0)
                
                if existing_size == file_size:
                    return {
                        "success": True,
                        "can_fast_upload": True,
                        "message": "文件已存在且大小相同",
                        "file_id": existing_file.get("id")
                    }
                else:
                    return {
                        "success": True,
                        "can_fast_upload": False,
                        "message": "文件已存在但大小不同，需要覆盖上传"
                    }
            else:
                return {
                    "success": True,
                    "can_fast_upload": False,
                    "message": "文件不存在，需要上传"
                }
                
        except Exception as e:
            return {"success": False, "error": f"检查秒传异常: {str(e)}"}
    
    def fast_upload(self, file_path: str, parent_file_id: str = "root") -> Dict[str, Any]:
        """执行文件秒传
        
        Args:
            file_path: 本地文件路径
            parent_file_id: 父文件夹ID，默认为根目录
            
        Returns:
            秒传结果
        """
        try:
            # 先检查是否可以秒传
            check_result = self.check_fast_upload(file_path, parent_file_id)
            
            if not check_result["success"]:
                return check_result
            
            if check_result["can_fast_upload"]:
                return {
                    "success": True,
                    "message": "文件秒传成功（文件已存在）",
                    "file_id": check_result["file_id"]
                }
            else:
                return {
                    "success": False,
                    "error": "文件不支持秒传，需要普通上传"
                }
                
        except Exception as e:
            return {"success": False, "error": f"秒传异常: {str(e)}"}
    
    def upload_file(self, file_path: str, remote_path: str = "/", parent_file_id: str = "root") -> Dict[str, Any]:
        """上传文件
        
        Args:
            file_path: 本地文件路径
            remote_path: 远程路径（暂时未使用）
            parent_file_id: 父文件夹ID，默认为根目录
            
        Returns:
            上传结果
        """
        try:
            if not os.path.exists(file_path):
                return {"success": False, "error": "文件不存在"}
            
            # 先尝试秒传
            fast_result = self.fast_upload(file_path, parent_file_id)
            if fast_result["success"]:
                return fast_result
            
            # 秒传失败，执行普通上传
            file_size = os.path.getsize(file_path)
            
            # 根据文件大小选择上传方式
            if file_size <= 4 * 1024 * 1024:  # 4MB以下使用简单上传
                return self._simple_upload(file_path, parent_file_id)
            else:  # 4MB以上使用分片上传
                return self._resumable_upload(file_path, parent_file_id)
                
        except Exception as e:
            return {"success": False, "error": f"上传文件异常: {str(e)}"}
    
    def _simple_upload(self, file_path: str, parent_file_id: str) -> Dict[str, Any]:
        """简单上传（小文件）
        
        Args:
            file_path: 本地文件路径
            parent_file_id: 父文件夹ID
            
        Returns:
            上传结果
        """
        try:
            file_name = os.path.basename(file_path)
            
            if parent_file_id == "root":
                url = f"https://graph.microsoft.com/v1.0/me/drive/root:/{file_name}:/content"
            else:
                url = f"https://graph.microsoft.com/v1.0/me/drive/items/{parent_file_id}:/{file_name}:/content"
            
            headers = {
                "Authorization": f"Bearer {self.client.access_token}",
                "Content-Type": "application/octet-stream"
            }
            
            with open(file_path, 'rb') as f:
                response = self.session.put(url, headers=headers, data=f)
            
            if response.status_code in [200, 201]:
                result = response.json()
                return {
                    "success": True,
                    "message": "文件上传成功",
                    "file_id": result.get("id")
                }
            else:
                return {"success": False, "error": f"简单上传失败: {response.text}"}
                
        except Exception as e:
            return {"success": False, "error": f"简单上传异常: {str(e)}"}
    
    def _resumable_upload(self, file_path: str, parent_file_id: str) -> Dict[str, Any]:
        """可恢复上传（大文件）
        
        Args:
            file_path: 本地文件路径
            parent_file_id: 父文件夹ID
            
        Returns:
            上传结果
        """
        try:
            file_name = os.path.basename(file_path)
            file_size = os.path.getsize(file_path)
            
            # 创建上传会话
            upload_session = self._create_upload_session(file_name, parent_file_id)
            if not upload_session["success"]:
                return upload_session
            
            upload_url = upload_session["upload_url"]
            
            # 分片上传
            chunk_size = 320 * 1024  # 320KB per chunk (must be multiple of 320KB)
            
            with open(file_path, 'rb') as f:
                offset = 0
                while offset < file_size:
                    chunk_end = min(offset + chunk_size, file_size)
                    chunk_data = f.read(chunk_end - offset)
                    
                    headers = {
                        "Content-Length": str(len(chunk_data)),
                        "Content-Range": f"bytes {offset}-{chunk_end-1}/{file_size}"
                    }
                    
                    response = self.session.put(upload_url, headers=headers, data=chunk_data)
                    
                    if response.status_code == 202:
                        # 继续上传下一个分片
                        offset = chunk_end
                    elif response.status_code in [200, 201]:
                        # 上传完成
                        result = response.json()
                        return {
                            "success": True,
                            "message": "文件上传成功",
                            "file_id": result.get("id")
                        }
                    else:
                        return {"success": False, "error": f"分片上传失败: {response.text}"}
            
            return {"success": False, "error": "上传未完成"}
            
        except Exception as e:
            return {"success": False, "error": f"可恢复上传异常: {str(e)}"}
    
    def _create_upload_session(self, file_name: str, parent_file_id: str) -> Dict[str, Any]:
        """创建上传会话
        
        Args:
            file_name: 文件名
            parent_file_id: 父文件夹ID
            
        Returns:
            上传会话信息
        """
        try:
            if parent_file_id == "root":
                url = f"https://graph.microsoft.com/v1.0/me/drive/root:/{file_name}:/createUploadSession"
            else:
                url = f"https://graph.microsoft.com/v1.0/me/drive/items/{parent_file_id}:/{file_name}:/createUploadSession"
            
            headers = {
                "Authorization": f"Bearer {self.client.access_token}",
                "Content-Type": "application/json"
            }
            
            data = {
                "item": {
                    "@microsoft.graph.conflictBehavior": "replace",
                    "name": file_name
                }
            }
            
            response = self.session.post(url, headers=headers, json=data)
            
            if response.status_code == 200:
                result = response.json()
                return {
                    "success": True,
                    "upload_url": result.get("uploadUrl")
                }
            else:
                return {"success": False, "error": f"创建上传会话失败: {response.text}"}
                
        except Exception as e:
            return {"success": False, "error": f"创建上传会话异常: {str(e)}"}
    
    def _calculate_file_hash(self, file_path: str) -> str:
        """计算文件哈希值
        
        Args:
            file_path: 文件路径
            
        Returns:
            文件的哈希值
        """
        sha1_hash = hashlib.sha1()
        with open(file_path, 'rb') as f:
            for chunk in iter(lambda: f.read(4096), b""):
                sha1_hash.update(chunk)
        return sha1_hash.hexdigest()